using Digitalmes.Common.Interfaces;
using Digitalmes.Domain.Entities.Mes.Processes;
using Digitalmes.Domain.Entities.Mes.Productions;
using Digitalmes.Domain.Entities.Mes.Qualities;
using Digitalmes.Domain.Entities.Mes.Reworks;

namespace Digitalmes.Application.Mes.Reworks.Doc.Commands;

/// <summary>
/// 在线返工单创建命令。
/// </summary>
public sealed record CreateOnlineReworkDocCommand(string Sn, long[] DefectIds, long TargetOperationId, string? Remark) : IRequest<IResult<bool>>;

internal sealed class CreateOnlineReworkDocCommandHandler(IRepository<ReworkDoc> repo,
    IRepository<ProdCurrentState> wipRepo,
    IRepository<QcDefectDefine> defectDefineRepo,
    IRepository<ProcOperation> operationRepo,
    IUniqueIdGenerator idGenerator,
    ICurrentUser currentUser)
    : IRequestHandler<CreateOnlineReworkDocCommand, IResult<bool>>
{
    public async Task<IResult<bool>> Handle(CreateOnlineReworkDocCommand request, CancellationToken cancellationToken)
    {
        // 查找产品
        var wip = await wipRepo.FirstOrDefaultAsync(m => m.Sn == request.Sn, cancellationToken);
        if (wip == null)
        {
            return Result.Failure("产品不存在");
        }
        if (!wip.IsNotGood())
        {
            return Result.Failure("产品非不合格状态，不能返工");
        }

        // 检查是否该产品已经存在未完成的返工单
        if (await repo.IsAnyAsync(m => m.Sn == request.Sn && (m.Status == ReworkStatusEnum.Created || m.Status == ReworkStatusEnum.Reworking), cancellationToken))
        {
            return Result.Failure("产品已存在未完成的返工单");
        }

        // 目标工序
        var operation = await operationRepo.GetByIdAsync(request.TargetOperationId, cancellationToken);
        if (operation == null)
        {
            return Result.Failure("未找到目标工序");
        }

        // 创建返工单
        ReworkDoc doc = new()
        {
            Id = idGenerator.NextId(),
            Sn = wip.Sn,
            ProductId = wip.ProductId,
            ProductCode = wip.ProductCode,
            Wo = wip.Wo,
            ReworkMode = ReworkModeEnum.Online,
            LineId = wip.LineId,
            NgOperationId = wip.OperationId,
            NgOperationCode = wip.OperationCode,
            NgWorkstationId = wip.WorkstationId,
            NgWorkstationCode = wip.WorkstationCode,
            TargetOperationId = request.TargetOperationId,
            TargetOperationCode = operation.OpCode,
            Status = ReworkStatusEnum.Created,
            Result = ReworkResultEnum.Qualified,
            Operator = currentUser.Username,
            Remark = request.Remark,
            StartTime = DateTime.Now
        };

        // 缺陷
        if (request.DefectIds.Length > 0)
        {
            var defectDefines = await defectDefineRepo.GetListAsync(m => request.DefectIds.Contains(m.Id), cancellationToken);
            doc.Defects = [.. defectDefines.Select(m => new ReworkDefect
            {
                ReworkId = doc.Id,
                DefectId = m.Id,
                DefectCode = m.DefectCode,
                DefectName = m.DefectName,
                DefectType = m.DefectType,
                DefectTypeDesc = m.DefectTypeDesc,
                DefectLevel = m.DefectLevel,
            })];
        }

        var ok = await repo.Context.InsertNav(doc).Include(m => m.Defects).ExecuteCommandAsync();

        // 更新产品返工单
        wip.InReworkDocId = doc.Id;
        await wipRepo.UpdateAsync(wip, m => new
        {
            m.InReworkDocId,
        }, cancellationToken);

        return Result.From(ok);
    }
}
